import os
import shutil
import hashlib
import argparse
from pathlib import Path
from filecmp import dircmp

def get_file_hash(file_path, block_size=65536):
    """计算文件哈希值，用于比较文件是否相同"""
    sha256 = hashlib.sha256()
    with open(file_path, 'rb') as f:
        while True:
            block = f.read(block_size)
            if not block:
                break
            sha256.update(block)
    return sha256.hexdigest()

def sync_directories(source, target, bidirectional=False, delete=False):
    """
    同步两个目录
    :param source: 源目录
    :param target: 目标目录
    :param bidirectional: 是否双向同步
    :param delete: 是否删除目标中不存在于源的文件
    """
    try:
        # 确保目录存在
        Path(source).mkdir(parents=True, exist_ok=True)
        Path(target).mkdir(parents=True, exist_ok=True)
        
        # 比较目录
        dcmp = dircmp(source, target)
        
        # 复制源目录独有的文件
        for file in dcmp.left_only:
            src_path = os.path.join(dcmp.left, file)
            dest_path = os.path.join(dcmp.right, file)
            if os.path.isdir(src_path):
                shutil.copytree(src_path, dest_path)
                print(f"复制目录: {src_path} -> {dest_path}")
            else:
                shutil.copy2(src_path, dest_path)
                print(f"复制文件: {src_path} -> {dest_path}")
        
        # 双向同步：复制目标目录独有的文件到源
        if bidirectional:
            for file in dcmp.right_only:
                src_path = os.path.join(dcmp.right, file)
                dest_path = os.path.join(dcmp.left, file)
                if os.path.isdir(src_path):
                    shutil.copytree(src_path, dest_path)
                    print(f"双向复制目录: {src_path} -> {dest_path}")
                else:
                    shutil.copy2(src_path, dest_path)
                    print(f"双向复制文件: {src_path} -> {dest_path}")
        
        # 更新不同的文件
        for file in dcmp.diff_files:
            src_path = os.path.join(dcmp.left, file)
            dest_path = os.path.join(dcmp.right, file)
            
            # 比较哈希值确认是否真的不同
            if get_file_hash(src_path) != get_file_hash(dest_path):
                shutil.copy2(src_path, dest_path)
                print(f"更新文件: {src_path} -> {dest_path}")
                
                # 双向同步时也更新反向
                if bidirectional:
                    shutil.copy2(dest_path, src_path)
                    print(f"双向更新文件: {dest_path} -> {src_path}")
        
        # 递归处理子目录
        for subdir in dcmp.common_dirs:
            sync_directories(
                os.path.join(source, subdir),
                os.path.join(target, subdir),
                bidirectional,
                delete
            )
        
        # 删除目标中不存在于源的文件
        if delete and not bidirectional:
            for file in dcmp.right_only:
                path = os.path.join(dcmp.right, file)
                if os.path.isdir(path):
                    shutil.rmtree(path)
                    print(f"删除目录: {path}")
                else:
                    os.remove(path)
                    print(f"删除文件: {path}")
        
        print("\n同步完成")
        
    except Exception as e:
        print(f"同步失败: {str(e)}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='文件同步工具')
    parser.add_argument('source', help='源目录')
    parser.add_argument('target', help='目标目录')
    parser.add_argument('--bidirectional', action='store_true', help='双向同步')
    parser.add_argument('--delete', action='store_true', help='删除目标中源不存在的文件')
    
    args = parser.parse_args()
    
    sync_directories(
        source=args.source,
        target=args.target,
        bidirectional=args.bidirectional,
        delete=args.delete
    )
